package org.jvending.provisioning.portal;

import org.jvending.provisioning.xml.discovery.Bundles;
import org.jvending.provisioning.xml.discovery.BundlesType;
import org.jvending.provisioning.xml.discovery.ObjectFactory;

import javax.provisioning.BundleDescriptor;
import javax.provisioning.Deliverable;
import javax.provisioning.MatchPolicy;
import javax.provisioning.ProvisioningContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Calendar;
import java.util.logging.Logger;

public class AndroidDiscoveryServlet extends HttpServlet {

    private static Logger logger = Logger.getAnonymousLogger();

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {
        String serverURI = this.getServletContext().getInitParameter("CONTENT_DELIVERY_URI");

        ProvisioningContext provisioningContext = (ProvisioningContext)
                this.getServletContext().getAttribute("javax.provisioning.ProvisioningContext");

        List<MatchPolicy> matchPolicies = new ArrayList<MatchPolicy>();
        matchPolicies.add(new MatchPolicy() {
            public float doMatch(BundleDescriptor bd) {
                Deliverable descriptorFile = bd.getDescriptorFile();
                if (descriptorFile == null) {
                    return 0;
                }
                if ("application/vnd.oma.dd2+xml".equals(descriptorFile.getMimeType())) {
                    return 1;
                }
                return 0;
            }
        });

        Collection<BundleDescriptor> bundleDescriptors =
                provisioningContext.getBundleRepository().getBundlesFor(null, matchPolicies);
        OutputStream os = response.getOutputStream();
        response.setContentType("text/xml");

        ObjectFactory factory = new ObjectFactory();
        BundlesType.Bundle bundle = null;
        try {
            Bundles bundles = factory.createBundles();
            for (BundleDescriptor bundleDescriptor : bundleDescriptors) {
                bundle = factory.createBundlesTypeBundle();
                String bundleId = bundleDescriptor.getBundleID();

                bundle.setBundleId(bundleId);
                String category = bundleDescriptor.getCatalogProperty("Category");
                if (category == null) {
                    logger.info("Excluding content from android discovery. Missing category: Bundle Id = " + bundleId);
                    continue;
                }
                
                if (category.length() > 16) {
                    category = category.substring(0, 15);
                }
                bundle.setCategory(category);

                bundle.setContentURI(serverURI + "/AdapterController?bundleId=" + bundleId);

                String displayName = bundleDescriptor.getDisplayName(null);
                if (displayName != null && displayName.length() > 20) {
                    displayName = displayName.substring(0, 19);
                }
                bundle.setDisplayName(displayName);

                List<Deliverable> icons = bundleDescriptor.getIcons(null);
                if (!icons.isEmpty()) {
                    bundle.setIcon(icons.get(0).getURL().toString());
                }
                String longDescription = bundleDescriptor.getDescription(null);
                if (longDescription != null && longDescription.length() > 248) {
                    longDescription = longDescription.substring(0, 247) + "...";
                }
                bundle.setLongDescription(longDescription);

                String price = bundleDescriptor.getCatalogProperty("Price");
                if (price == null) {
                    price = "Free";
                }

                if (price.length() > 6) {
                    price = price.substring(0, 5);
                }
                bundle.setPrice(price);

                String shortDescription = bundleDescriptor.getCatalogProperty("Short Description");
                if (shortDescription == null) {
                    shortDescription = bundle.getLongDescription();
                }
                if (shortDescription.length() > 50) {
                    shortDescription = shortDescription.substring(0, 49) + "...";
                }
                bundle.setShortDescription(shortDescription);

                String copyright = bundleDescriptor.getCopyright(null);
                if (copyright == null) {
                    copyright = "No Terms Specified";
                }
                if (copyright.length() > 248) {
                    copyright = copyright.substring(0, 247) + "...";
                }
                bundle.setTermsAndConditions(copyright);

                String vendorName = bundleDescriptor.getVendor(null);
                if (vendorName != null && vendorName.length() > 10) {
                    vendorName = vendorName.substring(0, 9);
                }
                bundle.setVendorName(vendorName);

                String version = bundleDescriptor.getVersion();
                if (version != null && version.length() > 10) {
                    version = version.substring(0, 9);
                }
                bundle.setVersion(version);

                Calendar c = Calendar.getInstance();
                c.setTimeInMillis(bundleDescriptor.getUploadTime());
                String date = (c.get(Calendar.MONTH) + 1) + "/" + (c.get(Calendar.DAY_OF_MONTH) + 1)
                        + "/" + c.get(Calendar.YEAR);
                bundle.setCreationDate(date);

                if (verifyBundle(bundle)) {
                    bundles.getBundle().add(bundle);
                } else {
                    logger.info(bundleToString(bundle));
                }
            }

            JAXBContext jaxbContext = JAXBContext.newInstance("org.jvending.provisioning.xml.discovery");
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.marshal(bundles, os);
        } catch (JAXBException e) {
            e.printStackTrace();
            logger.severe("Unable to process catalog: " + bundleToString(bundle));
            response.sendError(404, "Unable to process catalog");
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    private static String bundleToString(BundlesType.Bundle bundle) {
        if (bundle == null)
            return "";

        StringBuffer sb = new StringBuffer();
        sb.append("Bundle not valid. Bundle Id = ").
                append(bundle.getBundleId()).
                append("\r\nCategory = ").append(bundle.getCategory()).
                append("\r\nContent URI = ").append(bundle.getContentURI()).
                append("\r\nDisplay Name = ").append(bundle.getDisplayName()).
                append("\r\nLong Description = ").append(bundle.getLongDescription()).
                append("\r\nShort Description = ").append(bundle.getShortDescription()).
                append("\r\nPrice = ").append(bundle.getPrice()).
                append("\r\nTerms = ").append(bundle.getTermsAndConditions()).
                append("\r\nVendor Name = ").append(bundle.getVendorName()).
                append("\r\nVersion = ").append(bundle.getVersion());
        return sb.toString();
    }

    private static boolean verifyBundle(BundlesType.Bundle bundle) {
        return bundle.getBundleId() != null && bundle.getCategory() != null && bundle.getContentURI() != null &&
                bundle.getDisplayName() != null && bundle.getLongDescription() != null && bundle.getShortDescription() != null
                && bundle.getPrice() != null && bundle.getTermsAndConditions() != null && bundle.getVendorName() != null
                && bundle.getVersion() != null;
    }

    public final void writeContents(OutputStream os) throws IOException {

    }
}
